package main

import (
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"math/big"
	"os"
	"path"

	"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
	log "github.com/sirupsen/logrus"
)

var uploadedSize *big.Int

/*
@Description:blob连接
@return *azblob.ContainerClient
*/
func ConnBlob(ContainerClient string) (*azblob.ContainerClient, error) {

	connStr := "DefaultEndpointsProtocol=https;AccountName=yingshi;AccountKey=cPvXkZrjoRggH2b1/4/BxTQxHLqhoXD1O7C1ncCk+luOhKqz/vS3pgCRVDdIMFVJwarBmI4moNGBbegCuw1UXA==;EndpointSuffix=core.chinacloudapi.cn"
	client, err := azblob.NewServiceClientFromConnectionString(connStr, nil)
	if err != nil {
		log.Error("认证错误", err)
		return nil, err
	}
	containerClient, _ := client.NewContainerClient(ContainerClient)
	_, err = containerClient.Create(context.TODO(), nil)
	return containerClient, nil
}

/*
	LookList

@Description:查看指定容器中存放的所有文件
@param containerClient
*/
func LookList(containerClient *azblob.ContainerClient) {
	count := 0
	pager := containerClient.ListBlobsFlat(nil)
	for pager.NextPage(context.TODO()) {
		resp := pager.PageResponse()
		for _, v := range resp.Segment.BlobItems {
			fmt.Println(*v.Name)
			count++
		}
	}
	fmt.Printf("总数：%d", count)
}

// DelContain
// @Description: 清空指定容器中所有文件
// @param containerClient
func DelContain(containerClient *azblob.ContainerClient) {
	_, err := containerClient.Delete(context.TODO(), nil)
	if err != nil {
		log.Error(err)
	}
}

type BlobContainerClient struct {
	ContainerClient *azblob.ContainerClient
}

// UploadFile
// @Description: 上传单个文件
// @receiver blobContainerClient
// @param filePath 文件路径
// @param BlobAdd 目标基路径
// @return error
func (blobContainerClient BlobContainerClient) UploadFile(filePath string, BlobAdd string) error {
	fileName := path.Base(filePath)
	blobPath := path.Join(BlobAdd, fileName)
	blockBlobClient, err := blobContainerClient.ContainerClient.NewBlockBlobClient(blobPath)

	// Upload file to blob
	file, _ := os.Open(filePath)
	fileSize, err := file.Stat()
	if err != nil {
		log.Error(err)
		return err
	}
	if fileSize.Size() == 0 {
		log.Infof("文件:%s 大小为0", filePath)
		return nil
	}
	_, err = blockBlobClient.UploadFile(context.TODO(), file,
		azblob.UploadOption{
			// If Progress is non-nil, this function is called periodically as bytes are uploaded.
			Progress: func(bytesTransferred int64) {
				log.Infof("Uploaded %d of %d bytes.", bytesTransferred, fileSize.Size())

			},
		})
	uploadedSize.Add(uploadedSize, big.NewInt(fileSize.Size()))
	if err != nil {
		log.Error(err)
		return err
	}
	return nil
}

// UploadDir
// @Description: 上传指定的文件夹到blob上
// @receiver blobContainerClient
// @param dirPath 文件夹路径
// @param blobAdd 目标基路径
// @param process 进度条控件
// @param isupload 是否需要继续上传
// @return error
func (blobContainerClient BlobContainerClient) UploadDir(dirPath string, blobAdd string, isupload *bool) error {
	dirSize, err := GetDirSize(dirPath)
	if err != nil {
		return errors.New("已扫描的照片文件夹不存在" + dirPath)
	} else {
		log.Infof("%s目录下所有文件大小为%s", dirPath, dirSize.String())

	}
	uploadedSize = big.NewInt(int64(0))
	err = traversalUploadDir(dirPath, blobAdd, blobContainerClient.ContainerClient, dirSize, isupload)
	if err != nil {
		return errors.New("已扫描的照片文件夹不存在" + dirPath)
	}
	return nil
}

/*
@Description:上传单个文件
@param containerClient
@param filePath 需要上传文件的地址
@param uploadDir 上传文件的blob地址
@return error
*/
func UploadFile(containerClient *azblob.ContainerClient, filePath string, uploadDir string, totalSize *big.Int) error {
	fileName := path.Base(filePath)
	blobPath := path.Join(uploadDir, fileName)
	blockBlobClient, err := containerClient.NewBlockBlobClient(blobPath)
	//if err != nil {
	//	log.Error(err)
	//}

	// Upload file to blob
	file, _ := os.Open(filePath)
	fileSize, err := file.Stat()
	if err != nil {
		log.Error(err)
		return err
	}
	if fileSize.Size() == 0 {
		log.Infof("文件:%s 大小为0", filePath)
		return nil
	}
	_, err = blockBlobClient.UploadFile(context.TODO(), file,
		azblob.UploadOption{
			// If Progress is non-nil, this function is called periodically as bytes are uploaded.
			Progress: func(bytesTransferred int64) {

				log.Infof("Uploaded %d of %d bytes.", bytesTransferred, fileSize.Size())

			},
		})
	uploadedSize.Add(uploadedSize, big.NewInt(fileSize.Size()))
	if err != nil {
		log.Error(err)
		return err
	}
	return nil
}

/*
traversalUploadDir
@Description:递归遍历当前文件夹下所有文件并上传
@param dir 文件夹路径
@param uploadDir 上传的blob地址
@param containerClient
@param ProgressBar 进度条控件
@return error
*/
func traversalUploadDir(dir string, uploadDir string, containerClient *azblob.ContainerClient, totalSize *big.Int, isupload *bool) error {
	if !*isupload {
		return nil
	}
	fileinfo, err := ioutil.ReadDir(dir)

	if err != nil {
		log.Error(err)
		return err
	}
	for _, fi := range fileinfo {
		if !*isupload {
			return nil
		}
		if fi.IsDir() { //文件夹继续递归
			err = traversalUploadDir(path.Join(dir, fi.Name()), path.Join(uploadDir, fi.Name()), containerClient, totalSize, isupload)
			log.Infof("%s 文件夹已上传", dir)
			if err != nil {
				log.Error(err)
				return err
			}
		} else {
			err = UploadFile(containerClient, path.Join(dir, fi.Name()), uploadDir, totalSize)
			if err != nil {
				log.Error(err)
				return err
			}

			if err != nil {
				log.Error(err)
				return err
			} else {
				log.Infof("%s 文件已上传", path.Join(uploadDir, fi.Name()))
			}

		}
		if err != nil {
			return err
		}

	}
	return nil
}

/*
	TraversalCountDir

@Description: 递归统计文件夹下文件个数
@param dir 文件夹路径
@return int 文件个数
@return error 错误信息
*/
func TraversalCountDir(dir string) (*big.Int, error) {
	fileinfo, err := ioutil.ReadDir(dir)
	if err != nil {
		return big.NewInt(-1), err
	}
	countSize := big.NewInt(int64(0))
	for _, fi := range fileinfo {
		if fi.IsDir() { //文件夹继续递归
			dirSize, err := TraversalCountDir(path.Join(dir, fi.Name()))
			if err != nil {
				return big.NewInt(-1), err
			}
			countSize.Add(countSize, dirSize)
		} else {
			fileSzie, err := GetFileSize(path.Join(dir, fi.Name()))
			if err != nil {
				return big.NewInt(-1), err
			}
			countSize.Add(countSize, fileSzie)

		}
	}
	return countSize, nil
}
